package com.euond.accv.mdm.service;

import com.alibaba.fastjson.JSON;
import com.euond.accv.mdm.dao.BasCodeRuleDtlDao;
import com.euond.accv.mdm.domain.BasBillType;
import com.euond.accv.mdm.domain.BasCodeRule;
import com.euond.accv.mdm.domain.BasCodeRuleDtl;
import com.euond.common.exception.MyselfMsgException;
import com.euond.common.util.Collections3;
import com.euond.common.util.DateUtils;
import com.euond.common.util.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 
 * @Title
 * <p>Description: 获取单据号服务
 *1、根据单据类型获取单号
 *2、根据字段获取单据号
 *3、批量申请单据号</P>
 * @author tan.bin
 * @date   2016年11月3日
 *
 */
@Service
public class SystemCodeApiService {
	private static Logger logger = LoggerFactory.getLogger(SystemCodeApiService.class);

	@Autowired
	BasBillTypeService basBillTypeService;
	
	@Autowired
	BasCodeRuleService basCodeRuleService;
	
	@Autowired
	BasCodeRuleDtlService basCodeRuleDtlService;
	
	@Autowired
	BasCodeRuleDtlDao basCodeRuleDtlDao;

	
	/**
	 * 取日期
	 * 
	 * @param DateFormatValue
	 * @param cut_begin_position
	 * @param cut_end_position
	 * @param char_length
	 * @return
	 */
	public String getDateStr(String DateFormatValue, Integer cut_begin_position, Integer cut_end_position,
			Integer char_length) {
		String dateStr = DateUtils.formatDateByFormat(new Date(), DateFormatValue);
		if (cut_begin_position == 0 && cut_end_position == 0) {
			logger.info("日期------" + dateStr);
			return dateStr;
		}
		dateStr = dateStr.substring(cut_begin_position - 1,
				dateStr.length() < cut_end_position ? dateStr.length() : cut_end_position);
		logger.info("日期------" + dateStr);
		return dateStr;
	}
	/*
	 * 获取流水号
	 */
	public String doGetSerial(Long codeRuleId, Integer current_serial_no, Integer reset_mode, String pad_char,
			Integer char_length, Date current_serial_date) {

		Integer newCurrent_Serial_no = 1;// 新流水号
		String newSerial_no = "";
		// 判断流水日期是否空
		current_serial_date = current_serial_date != null ? current_serial_date : new Date();
		Date new_Serial_date = DateUtils.getCurrentDateTime();// 新流水时间
		if (reset_mode == 0) {// 永不重置
			newCurrent_Serial_no = current_serial_no + 1;
		}

		if (reset_mode == 1) {// 按天重置
			if (DateUtils.diffDate(new_Serial_date, current_serial_date) > 0) {
				newCurrent_Serial_no = 1;
			} else {
				newCurrent_Serial_no = current_serial_no + 1;
			}
		}

		if (reset_mode == 2) {// 按月重置

			// 先判当前年
			if (DateUtils.getYear(new_Serial_date) - DateUtils.getYear(current_serial_date) > 0) {

				newCurrent_Serial_no = 1;// 直接重置

			} else {

				if (DateUtils.getMonth(new_Serial_date) - DateUtils.getMonth(current_serial_date) > 0) {
					newCurrent_Serial_no = 1;
				} else {
					newCurrent_Serial_no = current_serial_no + 1;
				}
			}

		}

		if (reset_mode == 3) {// 按年重置
			if (DateUtils.getYear(new_Serial_date) - DateUtils.getYear(current_serial_date) > 0) {
				newCurrent_Serial_no = 1;
			} else {
				newCurrent_Serial_no = current_serial_no + 1;
			}
		}

		// 计算需要补位
		if (char_length >= newCurrent_Serial_no.toString().length()) {
			// 需要补的位数
			for (int i = 0; i < char_length - newCurrent_Serial_no.toString().length(); i++) {
				newSerial_no += pad_char;
			}
			newSerial_no += newCurrent_Serial_no.toString();
		}

		// 将流水和流水日期更新至数据库
		BasCodeRuleDtl codeRuleDtl = basCodeRuleDtlService.findOne(codeRuleId);
		codeRuleDtl.setCurrentSerialDate(new_Serial_date);
		codeRuleDtl.setCurrentSerialNo(newCurrent_Serial_no);

		basCodeRuleDtlService.update(codeRuleDtl);
		logger.info("流水号------" + newCurrent_Serial_no);
		return newSerial_no;
	}
	
	
	/**
	 * 
	 * @param billTypeNo 单据类型
	 * @return
	 */
	public String doGetSystemSheetid(String billTypeNo){
		LogUtils.logInfo(Thread.currentThread());
		// 验证
		BasBillType basBillType=basBillTypeService.findOne(billTypeNo);
		if(basBillType ==null){
			throw new MyselfMsgException("单据类型编号[" + billTypeNo + "]未在【单据类型】中维护");
		}
		String codeRuleNo = basBillType.getCodeRuleNo();
		BasCodeRule basCodeRule= basCodeRuleService.findOne(codeRuleNo);
		if(basCodeRule ==null){
			throw new MyselfMsgException("单据类型编号[" + billTypeNo + "]未在【编码规则】中维护");
		}

		// 先锁当前行，防止并发操作取到的单据号重复
		lockBasCodeRule(codeRuleNo);

		//根据codeRuleNo查找编码规则
		List<BasCodeRuleDtl> list = basCodeRuleDtlDao.findByCodeRuleNo(codeRuleNo);
		if(Collections3.isEmpty(list)){
			throw new MyselfMsgException("单据类型编号[" + billTypeNo + "]对应规则编号[" + codeRuleNo + "]未维护编码规则明细");
		}
		Long code_rule_id;// 主键
		Integer code_type = 1;// 编码类型
		Integer char_length = 0;// 字符
		Integer code_begin_position = 0;// 开始位置
		Integer cut_begin_position = 0;// 字符开始位置
		Integer cut_end_position = 1;// 字符结束位置
		String const_value = "";// 常量值
		String field_value = "";// 字段值
		Date current_serial_date = new Date();// 当前流水号日期
		Integer current_serial_no = 1;// 当前流水号
		Integer reset_mode = 0;// 流水号重置方式
		String pad_char = "0";// 补位符
		String SheetCode = "";// 生成的单据编码
		int endposition = 0;// 记录结束位置
		for (BasCodeRuleDtl m : list) {
			code_type = m.getCodeType();
			const_value = m.getConstValue();
			field_value = m.getFieldValue();
			char_length = m.getCharLength();
			code_begin_position = m.getCodeBeginPosition();

			cut_begin_position = m.getCutBeginPosition();
			cut_end_position = m.getCutEndPosition();

			current_serial_date = m.getCurrentSerialDate();
			current_serial_no = m.getCurrentSerialNo();
			reset_mode = m.getResetMode();
			pad_char = m.getPadChar();
			code_rule_id = m.getId();

			// 第n个编码位置{
			if (code_begin_position == endposition + 1) {// 取常量

				if (code_type == 1) {
					if (char_length == const_value.length()) {
						SheetCode += const_value;
					}
				}
				if (code_type == 2) {// 取日期

					SheetCode += getDateStr(m.getDateFormatValue(), cut_begin_position, cut_end_position, char_length);

				}
				/*单号获取不需要取字段
				 * if (code_type == 3) {// 取字段

					if (null != detial && !"".equals(detial) && !"".equals(field_value.trim())) {
						SheetCode += getfieldvalue(field_value, cut_begin_position, cut_end_position, char_length,
								detial);
					}

				}*/
				if (code_type == 4) {// 取流水

					SheetCode += doGetSerial(code_rule_id, current_serial_no, reset_mode, pad_char, char_length,
							current_serial_date);
				}
				endposition = m.getCodeEndPosition();// 记录结束位置
			}
		}
		return SheetCode;
	}

	/**
	 * 根据字段获取单据编号
	 * @param codeRuleNo
	 * @param detail
	 * @return
	 */
	public String getBillNoCodeRuleNo(String codeRuleNo,String detail){
		BasCodeRule codeRule = basCodeRuleService.findOne(codeRuleNo);
		if (codeRule == null) {
			throw new MyselfMsgException("规则编号[" + codeRuleNo + "]未在【编码规则】中维护");
		}

		// 先锁当前行，防止并发操作取到的单据号重复
		lockBasCodeRule(codeRuleNo);
		
		//获取编码规则明细
		List<BasCodeRuleDtl> list = basCodeRuleDtlDao.findByCodeRuleNo(codeRuleNo);
		if (Collections3.isEmpty(list)) {
			throw new MyselfMsgException("规则编号[" + codeRuleNo + "]未维护编码规则明细");
		}
		
		Long code_rule_id;// 主键
		int code_type = 1;// 编码类型
		int char_length = 0;// 字符
		int code_begin_position = 0;// 开始位置
		int cut_begin_position = 1;// 字符开始位置
		int cut_end_position = 1;// 字符结束位置
		String const_value = "";// 常量值
		String field_value = "";// 字段值
		Date current_serial_date = new Date();// 当前流水号日期
		int current_serial_no = 1;// 当前流水号
		int reset_mode = 0;// 流水号重置方式
		String pad_char = "0";// 补位符

		String SheetCode = "";// 生成的单据编码
		int endposition = 0;// 记录结束位置
		for (BasCodeRuleDtl bascode : list) {
			code_type = bascode.getCodeType();
			const_value = bascode.getConstValue();
			field_value = bascode.getFieldValue();
			char_length = bascode.getCharLength();
			code_begin_position = bascode.getCodeBeginPosition();

			cut_begin_position = bascode.getCutBeginPosition();
			cut_end_position = bascode.getCutEndPosition();

			current_serial_date = bascode.getCurrentSerialDate();
			current_serial_no = bascode.getCurrentSerialNo();
			reset_mode = bascode.getResetMode();
			pad_char = bascode.getPadChar();
			code_rule_id = bascode.getId();

			// 第n个编码位置{
			if (code_begin_position == endposition + 1) {// 取常量

				if (code_type == 1) {
					if (char_length == const_value.length()) {
						SheetCode += const_value;
					}
				}
				if (code_type == 2) {// 取日期

					SheetCode += getDateStr(bascode.getDateFormatValue(), cut_begin_position, cut_end_position,
							char_length);

				}
				if (code_type == 3) {// 取字段

					if (null != detail && !"".equals(detail) && !"".equals(field_value.trim())) {
						SheetCode += getfieldvalue(field_value, cut_begin_position, cut_end_position, char_length,
								detail);
					}
				}
				if (code_type == 4) {// 取流水

					SheetCode += doGetSerial(code_rule_id, current_serial_no, reset_mode, pad_char, char_length,
							current_serial_date);
				}
				endposition = bascode.getCodeEndPosition();// 记录结束位置
			}
		}
		return SheetCode;
	}

	/**
	 * 根据单据类型锁定单据编码规则表
	 * @param codeRuleNo
	 */
	private void lockBasCodeRule(String codeRuleNo){
		// 不能使用update进行锁单据，实体管理器并不一定刷新数据到数据库
		BasCodeRule newBasCodeRule = new BasCodeRule();
		newBasCodeRule.setCodeRuleNo(codeRuleNo);
		newBasCodeRule.setModifyTime(new Date());
		basCodeRuleService.updateByIdNames(newBasCodeRule, "");
	}

	/*
	 * 获取字段值
	 */
	public String getfieldvalue(String filelValue, Integer cut_begin_position, Integer cut_end_position,
			Integer char_length, String ParmValue) {

		String newFileValeu = "";
		if (JSON.parseObject(ParmValue).keySet().contains(filelValue)) {

			newFileValeu = JSON.parseObject(ParmValue).getString(filelValue);// 字段值
			newFileValeu = newFileValeu.substring(cut_begin_position - 1,
					newFileValeu.length() < cut_end_position ? newFileValeu.length() : cut_end_position);// 截取
			// if(newFileValeu.length()!=char_length){//截取长度必须等于设置字符
			// newFileValeu="";
			// }
		}
		logger.info("字段------" + newFileValeu);
		return newFileValeu;
	}

	
	/**
	 * 特殊化处理物料维护单生成物料编码， 剔除流水号、增加流水号长度值 物料编码专用
	 */
	@SuppressWarnings("unused")
	public Map<String, Object> getMaterialCodeRuleNo(Map<String, Object> params){
		String codeRuleNo = (String) params.get("codeRuleNo");
		String detail = (String) params.get("detail");// 字段集合

		List<BasCodeRuleDtl> list = basCodeRuleDtlDao.findByCodeRuleNo(codeRuleNo);
		if (Collections3.isEmpty(list)) {
			throw new MyselfMsgException("规则编号[" + codeRuleNo + "]未维护编码规则明细");
		}

		Long code_rule_id;// 主键
		int code_type = 1;// 编码类型
		int char_length = 0;// 字符
		int code_begin_position = 0;// 开始位置
		int cut_begin_position = 1;// 字符开始位置
		int cut_end_position = 1;// 字符结束位置
		String const_value = "";// 常量值
		String field_value = "";// 字段值
		int current_serial_no = 1;// 当前流水号
		int reset_mode = 0;// 流水号重置方式
		String pad_char = "0";// 补位符

		String code = "";// 生成的单据编码
		int serialLength = 0; // 流水号长度

		int endposition = 0;// 记录结束位置
		for (BasCodeRuleDtl bascode : list) {
			code_type = bascode.getCodeType();
			const_value = bascode.getConstValue();
			field_value = bascode.getFieldValue();
			char_length = bascode.getCharLength();
			code_begin_position = bascode.getCodeBeginPosition();

			cut_begin_position = bascode.getCutBeginPosition();
			cut_end_position = bascode.getCutEndPosition();

			current_serial_no = bascode.getCurrentSerialNo();
			reset_mode = bascode.getResetMode();
			pad_char = bascode.getPadChar();
			code_rule_id = bascode. getId();

			// 第n个编码位置{
			if (code_begin_position == endposition + 1) {// 取常量

				if (code_type == 1) {
					if (char_length == const_value.length()) {
						code += const_value;
					}
				}
				if (code_type == 2) {// 取日期

					code += DateUtils.formatDateByFormat(new Date(), bascode.getDateFormatValue()).substring(0,
							char_length);

				}
				if (code_type == 3) {// 取字段

					if (null != detail && !"".equals(detail) && !"".equals(field_value.trim())) {
						code += getfieldvalue(field_value, cut_begin_position, cut_end_position, char_length, detail);
					}
				}
				if (code_type == 4) {// 取流水
					serialLength = char_length;
					// SheetCode += getSerial(code_rule_id, current_serial_no,
					// reset_mode, pad_char, char_length, current_serial_date);
				}
				endposition = bascode.getCodeEndPosition();// 记录结束位置
			}
		}

		Map<String, Object> resultMap = new HashMap<>();
		resultMap.put("code", code);
		resultMap.put("serialLength", serialLength);

		return resultMap;
	}
	
	
	/**
	 * 批量获取单号
	 * 参数
	 * countNo 需要申请的单号的数据
	 * billtypeNo 单据编号
	 * 如我申请10个单据号 返回是beginNo:1 endNo:10
	 */
	public Map<String, Object> doGetBatchBillNo(Map<String, Object> parmMpa) {
		// TODO Auto-generated method stub
		 Map<String, Object> batchBillNo = new  HashMap<String, Object>();
		 String billTypeNo = parmMpa.get("billtypeNo").toString();//单据类别
		 String detial	   = parmMpa.get("detail").toString();//字段集合
		 Integer countNo   =Integer.parseInt(parmMpa.get("countNo").toString());//申请的流水数量

		 BasBillType basBillType = basBillTypeService.findOne(billTypeNo);
		 if(basBillType == null){
			 throw new MyselfMsgException("单据类型编号[" + billTypeNo + "]未在【单据类型】中维护");
		 }
	    String codeRuleNo = basBillType.getCodeRuleNo();
		BasCodeRule basCodeRule= basCodeRuleService.findOne(codeRuleNo);
		if(basCodeRule ==null){
			throw new MyselfMsgException("单据类型编号[" + billTypeNo + "]未在【编码规则】中维护");

		}
		 //用行锁，锁住行，不锁BasBillType，BasBillType为全局表，会报锁等待超时
		basCodeRule.setModifyTime(new Date());
		basCodeRuleService.update(basCodeRule);
		//根据codeRuleNo查找编码规则
		List<BasCodeRuleDtl> list = basCodeRuleDtlDao.findByCodeRuleNo(codeRuleNo);
		if(Collections3.isEmpty(list)){
			throw new MyselfMsgException("单据类型编号[" + billTypeNo + "]对应规则编号[" + codeRuleNo + "]未维护编码规则明细");
		}
		 Long code_rule_id;//主键
		 
		 Integer code_type=1;//编码类型
		 Integer char_length=0;//字符
		 Integer code_begin_position=0;//开始位置
		 Integer code_end_position=0;//结束位置
		 Integer cut_begin_position=0;//字符开始位置
		 Integer cut_end_position=1;//字符结束位置
		 String const_value="";//常量值
		 String date_format_value="yyyyMMdd";//日期格式化
		 String field_value="";//字段值
		 Date current_serial_date=new Date();//当前流水号日期
		 Integer current_serial_no=1;//当前流水号
		 Integer reset_mode=0;//流水号重置方式
		 String pad_char="0";//补位符
		 
		 String SheetCode="";//生成的单据编码
		 int endposition=0;//记录结束位置
		 String beginSerial="";
		 String endSerial="";
		 for(BasCodeRuleDtl bascode : list){
			 code_type=bascode.getCodeType();
			 const_value=bascode.getConstValue();
			 field_value=bascode.getFieldValue();
			 char_length=bascode.getCharLength();
			 code_begin_position=bascode.getCodeBeginPosition();

			 cut_begin_position=bascode.getCutBeginPosition();
			 cut_end_position=bascode.getCutEndPosition();
			 
			 current_serial_date =bascode.getCurrentSerialDate();
			 current_serial_no=bascode.getCurrentSerialNo();
			 reset_mode=bascode.getResetMode();
			 pad_char=bascode.getPadChar();
			 code_rule_id=bascode.getId();

			 
			 //第n个编码位置{
			 if(code_begin_position==endposition+1){//取常量
				 
				 if(code_type==1){
					 if(char_length==const_value.length()){
						 SheetCode+=const_value;
					 }
				 }if(code_type==2){//取日期
					 
					 SheetCode+=getDateStr(bascode.getDateFormatValue(),cut_begin_position,cut_end_position,char_length);
								 
				 }if(code_type==3){//取字段
					 
					 if(null !=detial && !"".equals(detial) && !"".equals(field_value.trim())){
						 SheetCode+=getfieldvalue(field_value,cut_begin_position,
								  cut_end_position,char_length,detial);
					 }

				 }if(code_type==4){//取流水
					 Map<String,Object> Serial =getBatchSerial(bascode,current_serial_no,countNo,reset_mode,pad_char,char_length,current_serial_date);
					 beginSerial=Serial.get("beginSerial").toString();
					 endSerial=Serial.get("endSerial").toString();
				 }
				 endposition=bascode.getCodeEndPosition();//记录结束位置
			 }
		 }
		 
		 batchBillNo.put("beginNo", SheetCode+beginSerial);
		 batchBillNo.put("endNo", SheetCode+endSerial);
		 return batchBillNo;
	 
	}
	
	 /*
	  * 批量取获取流水号
	  */
	 public Map<String,Object> getBatchSerial(BasCodeRuleDtl basCodeRuleDtl,Integer current_serial_no,Integer countNo,Integer reset_mode,
			 String pad_char,Integer char_length,Date current_serial_date){
		 
		 Map<String, Object> serial = new  HashMap<String, Object>();
		 Integer newCurrent_Serial_no=1;//新流水号
		 String  newSerial_no="";
		 String  newEndSerial_no="";
		 //判断流水日期是否空
		 current_serial_date=current_serial_date !=null?current_serial_date:new Date();
		 Date new_Serial_date = DateUtils.getCurrentDateTime();//新流水时间
		 if(reset_mode==0){//永不重置
			 newCurrent_Serial_no=current_serial_no+1;
		 }
		 
		 if(reset_mode==1){//按天重置
			 if(DateUtils.diffDate(new_Serial_date,current_serial_date)>0){
				 newCurrent_Serial_no=1;
			 }else{
				 newCurrent_Serial_no=current_serial_no+1;
			 }
		 }
		 
		 if(reset_mode==2){//按月重置

			//先判当前年
			 if(DateUtils.getYear(new_Serial_date)-DateUtils.getYear(current_serial_date)>0){
				 
				 newCurrent_Serial_no=1;//直接重置
				 
			 }else{
				 
				 if(DateUtils.getMonth(new_Serial_date)-DateUtils.getMonth(current_serial_date)>0){
					 newCurrent_Serial_no=1;
				 }else{
					 newCurrent_Serial_no=current_serial_no+1;
				 }
			 }
			
		 }
		 
		 if(reset_mode==3){//按年重置
			 if(DateUtils.getYear(new_Serial_date)-DateUtils.getYear(current_serial_date)>0){
				 newCurrent_Serial_no=1;
			 }else{
				 newCurrent_Serial_no=current_serial_no+1;
			 }
		 }
		 
		//计算需要补位
		 if(char_length>=newCurrent_Serial_no.toString().length()){
			 //需要补的位数
			 for(int i=0;i<char_length-newCurrent_Serial_no.toString().length();i++){
				 newSerial_no+=pad_char;
			 }
			 newSerial_no += newCurrent_Serial_no.toString();
		 }
		//先判断申请的单号的数据是否超出设置的流失位数 如 流失是4 申请的当前流失是1申请9999
		Integer endSerialNo =newCurrent_Serial_no+countNo;
		if(endSerialNo.toString().length()>char_length){
		
			throw new MyselfMsgException("申请的流水数量超过了设置的流水长度!!!!");

		}
		//累加后的流水也需要补位
		 if(char_length>=endSerialNo.toString().length()){
			 //需要补的位数
			 for(int i=0;i<char_length-endSerialNo.toString().length();i++){
				 newEndSerial_no+=pad_char;
			 }
			 newEndSerial_no += endSerialNo.toString();
		 }
		 logger.info("开始流水号------"+newSerial_no);
		 logger.info("结束流水号------"+newEndSerial_no);

		 //开始流水号
		 serial.put("beginSerial", newSerial_no);
		 //结束流水号
		 serial.put("endSerial", newEndSerial_no);
		 
		 //将流水和流水日期更新至数据库
		 basCodeRuleDtl.setCurrentSerialDate(new_Serial_date);
		 basCodeRuleDtl.setCurrentSerialNo(endSerialNo);//更新结束流水
		 basCodeRuleDtlDao.update(basCodeRuleDtl);
		 return serial;
	 }
	
	
}
